<template>
  <div class="table">
    <div class="dataTable" ref="dataTable">
      <el-table
        ref="multipleTable"
        v-loading="options.loading"
        :data="list"
        :stripe="options.stripe"
        :border="options.border"
        :default-sort="options.defaultSort"
        :row-style="options.rowStyle"
        :row-class-name="options.rowClassName"
        sticky
        :sticky-offset-top="80"
        v-horizontal-scroll="{bottom:42}"
        @row-click="rowClick"
        @sort-change='sortChange'
        @selection-change="handleSelectionChange">
        <el-table-column v-if="options.expand" type="expand">
          <template v-slot="props">
            <el-descriptions :column="options.expandColumn" :size="options.expandSize">
              <el-descriptions-item v-for="(column, index) in columns" :label="column.label" :key="index">
                <template v-if="column.formatter">
                  <span v-html="column.formatter(props.row, column)"/>
                </template>
                <template v-else>
                  <span v-html="props.row[column.prop]"></span>
                </template>
              </el-descriptions-item>
            </el-descriptions>
          </template>
        </el-table-column>
        <el-table-column
          type="index"
          label="序列"
          v-if="options.index"
          :align="options.align"
          width="50">
        </el-table-column>
        <!--选择框-->
        <el-table-column v-if="options.multipleSelect" type="selection" style="width: 55px;">
        </el-table-column>
        <!--数据列-->
        <template v-for="(column, index) in columns">
          <el-table-column
            :prop="column.prop"
            :label="column.label"
            :align="column.align"
            :header-align="column.align"
            :sortable="column.sortable"
            :resizable="column.resizable"
            :show-overflow-tooltip="column.showOverflowTooltip"
            :width="column.width"
            :fixed="column.fixed"
            v-if="!column.hide"
            :key="index">
            <template v-slot="scope">
              <template v-if="!column.render">
                <template v-if="column.formatter">
                  <span v-html="column.formatter(scope.row, column)"/>
                </template>
                <template v-else>
                  <span v-html="scope.row[column.prop]"></span>
                </template>
              </template>
              <template v-else>
                <expand-dom :column="column" :row="scope.row" :render="column.render" :index="index"/>
              </template>
            </template>
          </el-table-column>
        </template>
        <!--按钮操作组-->
        <el-table-column
          :label="operates.title===undefined?'操作':operates.title" align="center"
          :width="(operates.width===undefined || operates.width==='auto') && operates.list?operates.list.length*100:operates.width"
          :fixed="(device==='desktop')&&(operates.fixed===undefined?'right':operates.fixed)"
          v-if="(operates && operates.list && operates.list.length > 0 && operates.fixed)"
        >
          <template v-slot="scope">
            <div>
              <template v-for="(btn, key) in operates.list">
                <el-button
                  :type="btn.type" size="mini" :icon="btn.icon"
                  v-permission="btn.permission"
                  :disabled="btn.disabled(scope.$index,scope.row)"
                  :plain="btn.plain" @click.native.prevent="btn.method(key,scope.row)"
                  :key="key">
                  {{ btn.label }}
                </el-button>
              </template>
            </div>
          </template>
        </el-table-column>
        <el-table-column
          :label="operates.title===undefined?'操作':operates.title" align="center"
          :width="(operates.width===undefined || operates.width==='auto') && operates.list?operates.list.length*100:operates.width"
          v-else-if="(operates && operates.list && operates.list.length > 0)"
        >
          <template v-slot="scope">
            <div>
              <template v-for="(btn, key) in operates.list">
                <el-button
                  :type="btn.type" size="mini" :icon="btn.icon"
                  v-permission="btn.permission"
                  :disabled="btn.disabled(scope.$index,scope.row)"
                  :plain="btn.plain" @click.native.prevent="btn.method(key,scope.row)"
                  :key="key">
                  {{ btn.label }}
                </el-button>
              </template>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <!--分页-->
    <el-pagination
      class="pageRow" :style="{'text-align': device==='mobile'?'center':'right'}"
      v-if="pagination&&pagination.page"
      @size-change="handleSizeChange"
      @current-change="handleIndexChange"
      :page-size="pagination.pageSize"
      :small="device==='mobile'"
      :page-sizes="pagination.pageArray" :current-page="pagination.pageNum"
      :layout="device==='mobile'?'prev, pager, next, jumper':'total,sizes, prev, pager, next, jumper'"
      :hide-on-single-page="pagination.total<=10"
      :total="pagination.total"/>
  </div>
</template>
<script lang="ts">
import {Component, Emit, Prop, Vue} from 'vue-property-decorator';
import {Getter} from 'vuex-class';
import {filterParams} from '@/utils';
import erd from "element-resize-detector";
import {isEqual} from "lodash";

@Component({
  components: {
    expandDom: {
      functional: true,
      props: {
        row: Object,
        render: Function,
        index: Number,
        column: {
          type: Object,
          default: null
        }
      },
      render: (createElement: any, context: any) => {
        //详细使用方法见 https://cn.vuejs.org/v2/guide/render-function.html#createElement-%E5%8F%82%E6%95%B0
        const params = {
          row: context.props.row,
          index: context.props.index,
          column: ''
        };
        if (context.props.column) {
          params.column = context.props.column;
        }
        return context.props.render(createElement, params);
      }
    }
  }
})
export default class DataTable extends Vue {
  @Prop() private api!: any;
  @Prop() private columns!: Array<any>;// 需要展示的列 === prop：列数据对应的属性，label：列名，align：对齐方式，width：列宽,showOverflowTooltip:隐藏多余字符
  @Prop() private operates!: any;// width:按钮列宽，fixed：是否固定（left,right）,按钮集合 === label: 文本，type :类型（primary / success / warning / danger / info / text），show：是否显示，icon：按钮图标，plain：是否朴素按钮，disabled：是否禁用，method：回调方法
  @Prop({
    default: () => ({//分页参数
      pageNum: 1,
      pageSize: 10,
      pageArray: [10, 30, 50, 100],
      total: 0,
      page: true
    })
  })
  private pagination!: any;
  @Prop({
    default: () => ({//表格样式参数
      stripe: false, // 是否为斑马纹 table
      loading: false, // 是否添加表格loading加载动画
      highlightCurrentRow: false, // 是否支持当前行高亮显示
      multipleSelect: false, // 是否支持列表项选中功能
      defaultSort: {
        prop: 'id',
        order: 'descending'
      },
      border: false,
      expand: false,
      expandColumn: 3,
      expandSize: '',
      align: 'center',//对齐方式
      index: false,//是否显示序号
    })
  }) private options!: any;


  @Prop() private query: any;//查询参数
  @Getter('device') private device!: string;
  public list: Array<any> = [];
  public multipleSelection: Array<any> = [];// 多行选中
  @Prop({
    default: () => []
  })
  private defaultSelect!: any[];
  hQuery: any = {};//查询参数
  // 切换每页显示的数量
  handleSizeChange(size: number) {
    if (this.pagination) {
      this.pagination.pageNum = 1;
      this.pagination.pageSize = size;
      this.change();
    }
  }

  // 切换页码
  handleIndexChange(pageNum: number) {
    if (this.pagination) {
      this.pagination.pageNum = pageNum;
      this.change();
    }
  }

  sortChange(column: any) {
    if (column) {
      this.pagination.orderByColumn = column.prop;
      if (column.order === 'descending') {
        this.pagination.isAsc = 'desc';
      } else if (column.order === 'ascending') {
        this.pagination.isAsc = 'asc';
      } else {
        delete this.pagination['isAsc'];
      }
    } else {
      delete this.pagination['orderByColumn'];
      delete this.pagination['isAsc'];
    }
    this.change();
  }

  @Emit('update:pagination')
  change() {
    this.refresh();
    return this.pagination;
  }

  // 多行选中
  @Emit('handleSelectionChange')
  @Emit('handle-selection-change')
  handleSelectionChange(val: any) {
    this.multipleSelection = val;
    return val;
  }

  @Emit('rowClick')
  @Emit('row-click')
  rowClick(val: any) {
    return val;
  }

  toggleSelection(row: any) {
    if (row) {
      (this.$refs.multipleTable as any).toggleRowSelection(row);
    } else {
      (this.$refs.multipleTable as any).clearSelection();
    }
  }

  handleParams() {
    const options = Object.assign({}, this.query);
    if (!isEqual(this.hQuery, this.query)) {
      this.pagination.pageNum = 1;
      Object.assign(this.hQuery, this.query);
    }
    if (this.pagination) {
      options.pageNum = this.pagination.pageNum;
      options.pageSize = this.pagination.pageSize;
      options.orderByColumn = this.pagination.orderByColumn;
      options.isAsc = this.pagination.isAsc;
    }
    if (!options.orderByColumn) {
      options.orderByColumn = this.options.defaultSort ? this.options.defaultSort.prop || 'id' : 'id';
    }
    if (!options.isAsc) {
      if (this.options.defaultSort && this.options.defaultSort.order) {
        if (this.options.defaultSort.order === 'descending') {
          options.isAsc = 'desc';
        } else if (this.options.defaultSort.order === 'ascending') {
          options.isAsc = 'asc';
        } else {
          delete options.isAsc['isAsc'];
        }
      } else {
        options.isAsc = 'desc';
      }
    }
    return filterParams(options);
  }

  refreshData(api: any) {
    api(this.handleParams()).then((res: any) => {
      this.list = res.rows;
      this.pagination.total = res.total;
      this.handleEvent(res.rows);
      //判断是否选中
      if (this.defaultSelect?.length > 0) {
        this.$nextTick(() => {
          this.list.forEach(it => {
            this.defaultSelect.forEach(i => {
              if (it.id === i.id) {
                this.toggleSelection(it)
              }
            })
          })
        })
      }
    }).catch((e) => {
      console.error(e);
    });
  }

  @Emit('handleEvent')
  @Emit('handle-event')
  handleEvent(val) {
    return val;
  }

  refresh() {
    this.refreshData(this.api);
  }

  mounted() {
    this.onresize();
    this.refreshData(this.api);
  }

  $refs!: {
    multipleTable: HTMLFormElement,
    dataTable: HTMLDivElement
  };

  onresize() {
    const container = this.$refs.multipleTable?.$el;
    if (!container) {
      return;
    }
    erd().listenTo(container, () => {
      this.$nextTick(() => {
        if (this.$refs.dataTable) {
          this.$refs.dataTable.style.height = (this.$refs.multipleTable && this.$refs.multipleTable.$el.clientHeight + 1) + 'px';
        }
      })
    })
  }
}
</script>

<style scoped lang="scss">
.table {
  width: 100%;
  height: 100%;
  margin-top: 5px;

  .dataTable {
    position: relative;

    ::v-deep .el-table {
      position: absolute;
    }
  }

  .pageRow {
    margin: 10px;
    overflow: hidden;
  }
}
</style>

